﻿// -----------------------------------------------------------------------
// <copyright file="PushResult.cs" company="Zen Design Corp">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Zen.BlackBerry.Push
{
	using System;
	using System.Collections.Generic;
	using Zen.BlackBerry.Common;
	using Zen.BlackBerry.Pap;

	/// <summary>
	/// Represents the interim result of a push submission including the set of
	/// results for subscribers that failed to be pushed to due to an error on
	/// the PPG end, the sets of subscriber ids that were not sent to the PPG
	/// because they were invalid in some way (i.e. they do not exist, are
	/// inactive, or are suspended) and the approximate remaining quota for the
	/// day (in number of pushes). 
	/// </summary>
	/// <remarks>
	/// <para>
	/// Keep in mind, if your push application has a type of "Public+Enterprise Push",
	/// the push will potentially be sent to two PPGs (i.e. both the public/BIS
	/// and enterprise/BES PPG simultaneously) and therefore the getCode()
	/// method will return an approximated status. As a rule, if one or both
	/// PPGs accept the push request, the getCode() method will return ACCEPTED
	/// (except if DUPLICATE_PUSH_ID is returned, in which case, the push is
	/// considered failed). If both PPGs reject the push request, the public/BIS
	/// PPG status code will be returned.
	/// </para>
	/// <para>
	/// For a push application with a service level of Push Plus, the final
	/// outcome of the push delivery (i.e. whether the push was successfully
	/// received by the device/application) must be obtained by issuing a
	/// status query call or, if acknowledgements are being used, the result of
	/// the push will arrive asynchronously when the final outcome is known by
	/// the PPG.
	/// </para>
	/// <para>
	/// For a push application with a service level of Push Essentials, it is
	/// more difficult to determine the true status of a push since no querying
	/// APIs are available after the push is sent. The final delivery outcome
	/// to individual subscribers cannot be determined.
	/// </para>
	/// </remarks>
	public class PushResult
	{
		private IList<FailedPushResult> _failedPushResults;
		private ISet<string> _doNotExistSubscriberIds = new HashSet<string>();
		private ISet<string> _inactiveSubscriberIds = new HashSet<string>();
		private ISet<string> _suspendedSubscriberIds = new HashSet<string>();
		private List<PushOutcome> _outcomes = new List<PushOutcome>();

		/// <summary>
		/// Initializes a new instance of the <see cref="PushResult"/> class.
		/// </summary>
		/// <param name="pushId">The push id.</param>
		/// <param name="code">The code.</param>
		/// <param name="description">The description.</param>
		public PushResult(string pushId, string code, string description)
		{
			PushId = pushId;
			Code = StatusCode.GetCode(code);
			Description = description;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="PushResult"/> class.
		/// </summary>
		/// <param name="pushId">The push id.</param>
		/// <param name="code">The code.</param>
		public PushResult(string pushId, StatusCode code)
		{
			PushId = pushId;
			Code = code;
			Description = code.Description;
		}

		/// <summary>
		/// Gets the status code.
		/// </summary>
		/// <value>The status code.</value>
		public StatusCode Code
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets the description.
		/// </summary>
		/// <value>The description.</value>
		public string Description
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the push id.
		/// </summary>
		/// <value>The push id.</value>
		public string PushId
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the remaining quota.
		/// </summary>
		/// <value>The remaining quota.</value>
		public long RemainingQuota
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the do not exist subscriber ids.
		/// </summary>
		/// <value>The do not exist subscriber ids.</value>
		public ISet<string> DoNotExistSubscriberIds
		{
			get
			{
				if (_doNotExistSubscriberIds == null)
				{
					_doNotExistSubscriberIds = new HashSet<string>();
				}
				return _doNotExistSubscriberIds;
			}
			set
			{
				_doNotExistSubscriberIds = value;
			}
		}

		/// <summary>
		/// Gets or sets the subscriber ids that match inactive subscribers.
		/// </summary>
		/// <value>The inactive subscriber ids.</value>
		public ISet<string> InactiveSubscriberIds
		{
			get
			{
				if (_inactiveSubscriberIds == null)
				{
					_inactiveSubscriberIds = new HashSet<string>();
				}
				return _inactiveSubscriberIds;
			}
			set
			{
				_inactiveSubscriberIds = value;
			}
		}

		/// <summary>
		/// Gets or sets the subscriber ids that match suspended subscribers.
		/// </summary>
		/// <value>The suspended subscriber ids.</value>
		public ISet<string> SuspendedSubscriberIds
		{
			get
			{
				if (_suspendedSubscriberIds == null)
				{
					_suspendedSubscriberIds = new HashSet<string>();
				}
				return _suspendedSubscriberIds;
			}
			set
			{
				_suspendedSubscriberIds = value;
			}
		}

		/// <summary>
		/// Gets or sets the failed push results.
		/// </summary>
		/// <value>The failed push results.</value>
		public IList<FailedPushResult> FailedPushResults
		{
			get
			{
				if (_failedPushResults == null)
				{
					_failedPushResults = new List<FailedPushResult>();
				}
				return _failedPushResults;
			}
			set
			{
				_failedPushResults = value;
			}
		}

		/// <summary>
		/// Gets the address-specific push outcomes.
		/// </summary>
		/// <value>The outcomes.</value>
		public IList<PushOutcome> Outcomes
		{
			get
			{
				return _outcomes;
			}
		}

		/// <summary>
		/// Adds the outcome.
		/// </summary>
		/// <param name="address">The address.</param>
		/// <param name="statusCode">The status code.</param>
		/// <param name="description">The description.</param>
		/// <param name="eventTime">The event time.</param>
		/// <param name="messageState">State of the message.</param>
		/// <param name="isApplicationReliable">if set to <c>true</c> [is application reliable].</param>
		public void AddOutcome(
			string address,
			StatusCode statusCode,
			string description,
			DateTime eventTime,
			MessageState messageState,
			bool isApplicationReliable)
		{
			_outcomes.Add(new PushOutcome(
				address,
				statusCode,
				description,
				eventTime,
				messageState,
				isApplicationReliable));
		}
	}
}
